using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    class ConstantSelect : Component 
    {
        public NodeVector InNodes;
        public NodeVector OutNodes;
        public NodeVector SelIn;

        int iConstant;

        public ConstantSelect(Component poParentComponent, string psName, int piWidth, int piConstant)
            : base(poParentComponent, psName)
        {
            SelIn = this.CreateNodeVector("SEL_I", 1);
            InNodes = this.CreateNodeVector("DATA_I", piWidth);
            OutNodes = this.CreateNodeVector("DATA_O", piWidth);
            iConstant = piConstant;
        }

        public override void GenerateStructure()
        {
            Not oNotSelIn = null;

            string sConstant = Conversion.IntToBinaryString(iConstant, InNodes.Nodes.Count);
            int iConstLen = sConstant.Length - 1;

            for (int iBit = 0; iBit < InNodes.Nodes.Count; iBit++)
            {
                if (sConstant[iConstLen - iBit] == '0')
                {
                    if (oNotSelIn == null)
                    {
                        oNotSelIn = new Not(this, "not_sel");
                        oNotSelIn.InputNodes[0] = SelIn[0];
                    }
                    AndGate oAnd = new AndGate(this, "and" + iBit.ToString(), 2);
                    oAnd.InputNodes[0] = InNodes[iBit];
                    oAnd.InputNodes[1] = oNotSelIn.OutputNodes[0];
                    OutNodes[iBit] = oAnd.OutputNodes[0];
                }
                else
                {
                    OrGate oOr = new OrGate(this, "or" + iBit.ToString(), 2);
                    oOr.InputNodes[0] = InNodes[iBit];
                    oOr.InputNodes[1] = SelIn[0];
                    OutNodes[iBit] = oOr.OutputNodes[0];
                }
            }
        }

        protected override Component TestBuildStructure(Component poTopComponent, string psTestName)
		{
			return new ConstantSelect(poTopComponent,"testConstantSelect",4,2);
		}

        protected override string TestComponent(Clock poClock, Component poTestComponent, string psTestName)
        {
            string sTestId;
            string sExpect;
            string sGot;
            ConstantSelect oCSelect = (ConstantSelect)poTestComponent;

            sTestId = "select constant";
            sExpect = "0010";
            oCSelect.InNodes.NodeVectorAsString = "1010";
            oCSelect.SelIn.NodeVectorAsString = "1";
            sGot = oCSelect.OutNodes.NodeVectorAsString;
            if (sExpect != sGot)
                return sTestId + " - expected: " + sExpect + " got " + sGot;

            sTestId = "select input";
            sExpect = "1010";
            oCSelect.SelIn.NodeVectorAsString = "0";
            sGot = oCSelect.OutNodes.NodeVectorAsString;
            if (sExpect != sGot)
                return sTestId + " - expected: " + sExpect + " got " + sGot;

            sTestId = "select undefined";
            sExpect = "x010";
            oCSelect.InNodes.NodeVectorAsString = "1010";
            oCSelect.SelIn.NodeVectorAsString = "x";
            sGot = oCSelect.OutNodes.NodeVectorAsString;
            if (sExpect != sGot)
                return sTestId + " - expected: " + sExpect + " got " + sGot;

            sTestId = "input undefined, const selected";
            sExpect = "0010";
            oCSelect.InNodes.NodeVectorAsString = "101x";
            oCSelect.SelIn.NodeVectorAsString = "1";
            sGot = oCSelect.OutNodes.NodeVectorAsString;
            if (sExpect != sGot)
                return sTestId + " - expected: " + sExpect + " got " + sGot;

            sTestId = "input undefined, and selected";
            sExpect = "101x";
            oCSelect.InNodes.NodeVectorAsString = "101x";
            oCSelect.SelIn.NodeVectorAsString = "0";
            sGot = oCSelect.OutNodes.NodeVectorAsString;
            if (sExpect != sGot)
                return sTestId + " - expected: " + sExpect + " got " + sGot;

            return "";
        }


    }
}
